<script lang="ts" setup>
import { reactive, watch, onMounted } from 'vue';
import dayjs from 'dayjs';
import {
  Loading as AppNutIconLoading,
  Microphone as AppNutIconMicrophone,
  PlayStart as AppNutIconPlayStart,
  PlayStop as AppNutIconPlayStop,
} from '@nutui/icons-vue-taro';
import {
  showToast,
  showModal,
  getRecorderManager,
  uploadFile,
  createInnerAudioContext,
} from '@tarojs/taro';
import { UPLOAD_FILE } from '/@/api/modules/base/upload';
import { getSysImgUrl } from '/@/utils/index';
import { fileNameForUploadFile } from '/@/utils/file';
const props = withDefaults(
  defineProps<{
    /**
     * url
     */
    url?: string;
    /**
     * 只读
     */
    readonly?: boolean;
  }>(),
  {
    url: '',
    readonly: false,
  },
);

const emits = defineEmits<{
  (e: 'change', url: string, fileName: string): void;
}>();

const state = reactive<{
  /**
   * 录音中
   */
  inRecord: boolean;
  /**
   * 播放中
   */
  inPlay: boolean;
  /**
   * 音频在服务端的标识
   */
  url: string;
}>({
  inRecord: false,
  inPlay: false,
  url: '',
});

const recorderManager = getRecorderManager();
const innerAudioContext = createInnerAudioContext();
recorderManager.onStart(() => {
  state.inRecord = true;

  setTimeout(() => {
    if (!state.inRecord) return;
    recorderManager.stop();
    showToast({ title: '录音已超过60秒, 将停止录音!', icon: 'error' });
  }, 59000);
});
recorderManager.onStop((res) => {
  state.inRecord = false;
  const fileName = fileNameForUploadFile('.mp3');

  uploadFile({
    url: UPLOAD_FILE(),
    filePath: res.tempFilePath,
    fileName: fileName,
    name: 'file',
    formData: {
      uploadFileName: fileName,
      subPaths: `repair,
            ${dayjs().year()},
            ${dayjs().month() + 1},
            ${dayjs().date()}`,
      businessTag: 'service',
      uploadType: '3',
      type: '1',
    } as UploadFileApi.BaseReq,
    success(res) {
      const data: UploadFileApi.BaseResp = JSON.parse(res.data);

      state.url = data.subUrl;
      emits('change', state.url, fileName);
    },
  });
});
recorderManager.onError((res) => {
  showModal({ content: res.errMsg, showCancel: false });
});

innerAudioContext.autoplay = false;
innerAudioContext.onEnded(() => {
  state.inPlay = false;
});
innerAudioContext.onError((res) => {
  showModal({ content: res.errMsg, showCancel: false });
});

/**
 * @function 录音
 */
function handleRecorder() {
  if (state.inRecord) {
    recorderManager.stop();
    return;
  }

  recorderManager.start({
    duration: 60000,
    format: 'mp3',
  });
}

/**
 * @function 播放录音
 */
function handlePlay() {
  if (state.inPlay) {
    innerAudioContext.stop();
    state.inPlay = false;
    return;
  }

  innerAudioContext.src = getSysImgUrl(state.url);
  innerAudioContext.play();
  state.inPlay = true;
}

watch(props, (newProps) => {
  if (newProps.url) state.url = newProps.url;
});

onMounted(() => {
  state.url = props.url;
});
</script>

<template>
  <view class="app-wx-record-audio">
    <nut-button v-if="!props.readonly" size="small" type="info" @click="handleRecorder()">
      <template #icon>
        <app-nut-icon-loading v-if="state.inRecord" />
        <app-nut-icon-microphone v-else />
      </template>
      {{ state.inRecord ? '正在录音' : '点击开始说话' }}
    </nut-button>
    <nut-button v-if="state.url" type="info" size="small" @click="handlePlay()">
      <template #icon>
        <app-nut-icon-play-stop v-if="state.inPlay" />
        <app-nut-icon-play-start v-else />
      </template>
    </nut-button>
  </view>
</template>
